package wireless.xbee.arduino;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.util.Enumeration;


public class SerialComunication implements SerialPortEventListener {
       
       
        /*
         * action: Variável de controle, para saber se são comandos diferentes. Ex:
         * Ligar lampada: action = 1
         * Desligar lampada: action = 0
         *
         * Usando essa variavel foi feita uma lógica de modo que um comando de ligar não é
         * enviado após outro comando de ligar. Isso é feito pois não precisamos mandar
         * ligar uma lampâda que já esta ligada
         *
         *
         *
         * */
       
        /*
         * dados[]: Onde são guardados os dados recebidos. Como eu sei que o tamanho do vetor é 18?
         * Através de um teste. Enviei um pacote do arduino e criei um programinha para imprimir tudo
         * que chegar pela serial. Desse jeito eu vi o tamanho dos pacotes
         *
         *
         * */
       
       
       
       
        int action = 0;
        SerialPort serialPort;
        int dados[] = new int[18];


        private static final String PORT_NAMES[] = { "COM6" }; // Porta Usada
        // private static final String PORT_NAMES[] = { "/dev/tty.usbmodem411" }; //
       

        private static BufferedReader input;
        private static OutputStream output;
        private static final int TIME_OUT = 2000; // Milissegundos para bloqueio
                                                                                                // enquanto aguarda a porta
                                                                                                // abrir

        private static final int DATA_RATE = 9600; // baud rate da porta

        public void initialize() {
                CommPortIdentifier portId = null;
                Enumeration<?> portEnum = CommPortIdentifier.getPortIdentifiers();

                while (portEnum.hasMoreElements()) {
                        CommPortIdentifier currPortId = (CommPortIdentifier) portEnum
                                        .nextElement();
                        for (String portName : PORT_NAMES) {
                                if (currPortId.getName().equals(portName)) {
                                        portId = currPortId;
                                        break;
                                }
                        }
                }
                if (portId == null) {
                        System.out.println("\nPorta COM nao encontrada\n");
                        return;
                }

                try {
                        serialPort = (SerialPort) portId.open(this.getClass().getName(),
                                        TIME_OUT);

                        serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8,
                                        SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

                        input = new BufferedReader(new InputStreamReader(
                                        serialPort.getInputStream(),"ISO-8859-1"));         // Mudança de codificação padrão UTF-8 ( -127 a 127) para
                        serialPort.addEventListener((SerialPortEventListener) this);// ISO-8859-1 (0 a 255), pois o xbee envia de 0 a 255,
                                                                                                                                                // logo eu tenho que ler de 0 a 255
                        serialPort.notifyOnDataAvailable(true);
                } catch (Exception e) {
                        System.err.println(e.toString());
                }
        }

        /**
         * Deve ser chamado quando voc� parar de usar a porta. Evita travamento de
         * porta em plataformas Linux.
         */
        public synchronized void close() {
                if (serialPort != null) {
                        serialPort.removeEventListener();
                        serialPort.close();
                }
        }

        public synchronized void serialEvent(SerialPortEvent oEvent) {
               
                if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                       
                       
                        try {
                               
                                /*
                                 * aqui eu leio cada byte que ta do buffreader. 126 sempre eh o primeiro byte
                                 * do pacote, por isso eu só começo a guardar os dados no vetor quando eu acho
                                 * o 126. A informação útil do vetor será o data[15](temperatura) e o
                                 * data[16] luminosidade. As outras casas do vetor são informações de protocolo,
                                 * cabe salientar que eu recebo o endereço de quem me mando a mensagem que fica nas
                                 * casas dados[5] até dados[11].
                                 *
                                 * Aqui no caso eu estou fazendo o tratamendo da luminosidade, caso ela fique < 80
                                 * eu mando ligar a luz, senão fica apagada e faço aquela logica para não mandar
                                 * ligar uma coisa que já está ligada ou desligar uma coisa que já está desligada.
                                 *
                                 * Esse 80 da luz vem de uma normalizaçao que eu fuz no arduino, o xbee nao deixa
                                 * enviar dados maiores que 255 em um unico espaço do vetor. O range do ldr é
                                 * 0 - 1023. Ae como faz pra eu enviar isso pelo xbee? Eu podia quebrar em parte alta
                                 * e baixa e enviar em 2 casas o número, mas como eu quis simplificar ao máximo lá no
                                 * arduino, fiz uma normalização do range 0 - 1023 para 0 - 255, claro que eu perco
                                 * precisão com isso, mas isso NO MOMENTO pode ser desprezado.
                                 *
                                 *
                                 * */
       
                                int singleData =  input.read();                
                                if (singleData == 126) {
                                       
                                        dados[0] = singleData;
                                        for(int i=1;i<dados.length;i++) {
                                                dados[i] = input.read();
                                               
                                        }
                                       
                                        System.out.println(dados[16]);
                                        if (dados[16] < 80) {

                                                if(action != 1) {
                                                       
                                                        action = 1;
                                                        enviar(1);                                              
                                                }
       
                                        } else {
                                               
                                                if(action != 0) {
                                                        action = 0;
                                                        enviar(0);
                                               
                                                }
                                               
                                        }
                                       
                                       
                                }
                               

                        } catch (Exception e) {
                                System.err.println(e.toString());
                        }
                }

        }
       
        /* Método para enviar um dado ao arduino, UM DADO, digo isso porque caso você queira mandar
         * mais de um, você terá que alterar o número desta sequÊncia que indica quantos bits são enviados.
         * Alterando este número vc altera a posição do checksum e resumindo, nada é enviado. Eu sei,
         * este código não está nada genérico :(
         *
         * Pelo menos o calculo do valor do checksum é genérico, a fórmula tem no livro do Faludi sobre Xbee
         * e tem também na net, só dá uma procurada.
         *
         *
         * */
       
       
        public void enviar(int a) {
               
                try {
                       
                        output = serialPort.getOutputStream();
                       
                        int soma = 0;
                        int checksum = 0;
                        int dat[]={0x7E,0x00,15,0x10,0x00,0x00,0x13,0xA2,0x00,0x40,0xA9,0xC4,0xFC,0xFF,0xFE,0,0,a,113};
                       
                        for (int i = 3; i < ((dat.length) - 1); i++) {
                                soma = soma + dat[i];
                        }
                       
                        soma = soma % 256;
                        checksum = 0xFF - soma;
                        dat[18] = checksum;
                       
                        for (int i = 0; i <dat.length; i++) {
                                output.write(dat[i]);  
                        }
       
               
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
               
               
        }
       
        public static void main(String[] args) {
               
                SerialComunication app = new SerialComunication();
                app.initialize();

        }
}
